
//Copyright 1997-2009 Syrinx Development, Inc.
//This file is part of the Syrinx Web Application Framework (SWAF).
// == BEGIN LICENSE ==
//
// Licensed under the terms of any of the following licenses at your
// choice:
//
//  - GNU General Public License Version 3 or later (the "GPL")
//    http://www.gnu.org/licenses/gpl.html
//
//  - GNU Lesser General Public License Version 3 or later (the "LGPL")
//    http://www.gnu.org/licenses/lgpl.html
//
//  - Mozilla Public License Version 1.1 or later (the "MPL")
//    http://www.mozilla.org/MPL/MPL-1.1.html
//
// == END LICENSE ==
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;

using Swaf;
using Swaf.Gui;

using Swaf.BizObj;
using Swaf.Container;
using Swaf.Security;

namespace Articles.Gui
{
	public class ArticleManagementBizProc : BaseBusinessProcess
	{
		protected bool m_checkForValidPid = true;
		protected bool m_canChangeDetailsBizRule = true;
		//private IBizObjList m_currentArticleParentTree = null;
        protected string m_updateArtFormBizRule = "updateUserArtFormData";
		protected IBizObjList m_checkedArticles = null;
		protected Swaf.BGuid.Guid m_translationId = null;
		protected string m_userArtFormData = null;
		/// <summary>
		/// Used only when the bizproc has its useAssociationName set in its state, which means that
		/// the supplied pid is not the real pid for this bizproc.  This is the real pid.
		/// </summary>
		protected Swaf.BGuid.Guid m_realPid = null;

		public ArticleManagementBizProc(ActiveBizProc procState)
			:base(procState)
		{
		}

		public virtual string UseAssociationName
		{
			get
			{
				if (State == null)
					return null;
				string assName = (string)State.State.get("useAssociationName");
				if (!Cmn.IsEmpty(assName))
					return new StringBuilder(assName.Length + 25).Append("SysRootCore_").Append(assName).Append(",").Append(assName).Append(m_procState.get("pid")).ToString();
				return null;
			}
			set { if (State != null) State.State.put("useAssociationName",value); }
		}

        protected override void setupRuleNames()
		{
			base.m_getBizObjListRule = "getArticles";
			base.m_updateBizObjRule = "updateArticle";
			base.m_deleteBizObjRule = "deleteArticle";
		}

		//protected IBizObjList CurrentArticleParentTree
		//{
		//    get
		//    {
		//        if (m_currentBizObj != null)
		//        {
		//            if (m_currentArticleParentTree == null)
		//            {
		//                IResults rc = App.ruleMgr.execute("getBizObjTreeParents", "Articles", m_currentBizObj.get("id"), "DESC");
		//                m_currentArticleParentTree = rc.CallResults as IBizObjList;

		//            }
		//        }
		//        return m_currentArticleParentTree;
		//    }
		//}

		public override Privileges CurrentEditPrivilege
		{
			get 
			{
				object idx2 = m_procState.get("id");
				string idx = idx2==null?null:idx2.ToString();
				Privileges priv = Privileges.NotSet;
				bool usingArtPriv = m_currentBizObj != null;
				INameAddressSupport appFuns = (INameAddressSupport)CurrentPrincipal.get("AppFunctions");

				string id = m_currentBizObj == null?idx:m_currentBizObj.get("id").ToString();
				if (id != null)
				{
					if (appFuns.containsField(id))
						priv = (Privileges)appFuns.get(id);
					else if (m_currentBizObj != null)
					{
						if (m_currentBizObj.get("parentId") != null && appFuns.containsField(id = m_currentBizObj.get("parentId").ToString()))
							priv = (Privileges)appFuns.get(id);
						else if (m_currentBizObj.get("rootId") != null && appFuns.containsField(id = m_currentBizObj.get("rootId").ToString()))
							priv = (Privileges)appFuns.get(id);
						else
							priv = CurrentPrincipal.getPrivilege("AppFunctions.ManageArticles");
					}
				}

				if (priv == Privileges.NotSet)
				{
					idx2 = m_procState.get("pid");
					idx = idx2 == null ? null : idx2.ToString();
					if(!Cmn.IsEmpty(idx) && appFuns.containsField(idx))
						priv = (Privileges)appFuns.get(idx);
					else
						priv = CurrentPrincipal.getPrivilege("AppFunctions.ManageArticles");
				}
				return priv == Privileges.NotSet ? Privileges.None : priv; 
			}
		}

		public override void clearRetrievedData()
		{
			base.clearRetrievedData();
			m_realPid = null;
		}

		public override IBizObj createNewBizObj()
		{
			return setupNewBizObj(App.bizObjMgr.create(BizObjTypeName));
		}

		protected override string BizObjTypeName {get{return "Article";}}

		protected virtual IBizObj setupNewBizObj(IBizObj obj)
		{
			object pid = getActivePid(true);
			//if (m_realPid == null)
			if(pid == null)
			{
				if (CurrentBizObj != null)
					pid = CurrentBizObj.get("parentId");
			}

			if (pid is string)
			{
				if (!Cmn.IsEmpty(pid))
				{
					IResults rc = App.ruleMgr.execute("getArticleIdFromUniqueTitle", pid, ArticleTreeName);
					pid = rc.CallResults;
				}
				else
					pid = null;
			}
			obj.put("parentId", pid);
			obj.put("id", new Swaf.BGuid.Guid());
			//obj.put("baseTitle", "New Article");
			obj.put("counts.author.id", CurrentUser.get("id"));
			obj.put("treeName", ArticleTreeName);
			obj.put("companyId", ActiveCompanyId);
			return obj;
		}

		protected override object convertValueToKeyType(object val)
		{
			Swaf.BGuid.Guid id;

			if (val is Swaf.BGuid.Guid)
				return val;
			if (val!=null && Swaf.BGuid.Guid.TryParse(val.ToString(), out id))
				return id;
			if (val is string)
			{
				IResults rc = App.ruleMgr.execute("getArticleIdFromUniqueTitle", val, ArticleTreeName);
				return rc.CallResults;
			}
			return val;
		}

		protected override void getBizObjList()
		{
			//The test for no pid specified in the state ensures that we dont get the
			//entire tree of article unless that is what is really wanted. To get the
			//entire tree of articles the pid should be an empty string, not null.
			object pid = m_procState.get("pid");
			if (m_checkForValidPid && pid == null)
			{
				m_bizobjs = null;
				base.m_retrievedBizObjList = true;
			}
			else
				base.getBizObjList();

			if (m_bizobjs != null && m_bizobjs.numElements != 0)
			{
				//string firstTitle = m_bizobjs[0].get("title").ToString();
			}
		}

		protected override object[] calculateParentBizObjIds()
		{
			object[] pids = base.calculateParentBizObjIds();
			if (pids != null && pids.Length == 1)
			{
				pids[0] = getActivePid(false);
			}
			return pids;
		}

		protected virtual string ArticleTreeName { get { return "Articles"; } }

		protected virtual bool CreateParentsIfNoExist { get { return State == null ? false : Cmn.IsTrue(State.State.get("autoCreateParents")); } }

		protected virtual object getActivePid(bool forceCreate)
		{
				if (m_realPid == null && !(Cmn.IsEmpty(UseAssociationName)))
				{
					object pid = m_procState.get("pid");
					if (!Cmn.IsEmpty(pid))
						m_realPid = App.ruleMgr.execute("getRootAssociatedArticleId", UseAssociationName, forceCreate, ArticleTreeName).CallResults as Swaf.BGuid.Guid;
				}
				object retPid = m_realPid;
				if (retPid == null)
				{
					retPid = m_procState.get("pid");
					Swaf.BGuid.Guid strPid = null;
					if (retPid is string && (strPid = Swaf.BGuid.Guid.TryParse(retPid.ToString())) != null)
						retPid = strPid;

					if (CreateParentsIfNoExist && !(retPid is Swaf.BGuid.Guid))
						retPid = App.ruleMgr.execute("getRootAssociatedArticleId", retPid, true, ArticleTreeName).CallResults;
				}

				return Cmn.IsEmpty(retPid) ? null : retPid;
		}

		protected override object[] getBizObjListRuleParameters(object parentId, IBizObj filterSort)
		{
			FlexiMap m = new FlexiMap();
			//The following code allows the bizproc to set its pid='' and get the entire tree of all articles.
			//Without that, the entire tree can never be returned.
			object pid = parentId;
			if ("".Equals(pid))
				pid = null;
			//----------------------------------------------------
			if (pid is string && ((string)pid).Contains("$"))
			{
				string viewName = m_procState.BPC.HostView.ViewName;
				viewName = viewName.Substring(viewName.LastIndexOf('/')+1);
				if (viewName.EndsWith(".aspx"))
					viewName = viewName.Substring(0, viewName.Length - 5);
				pid = ((string)pid).Replace("$PageName$", viewName);
			}

			m.put("parentId", pid);
			object dl = State.State.get("listDetailLevel");
			if (dl is string)
				dl = (DetailLevel)Enum.Parse(typeof(DetailLevel), (string)dl);
			DetailLevel listLevel = (dl is DetailLevel) ? (DetailLevel)dl : DetailLevel.basicDetails;
			m.put("listDetailLevel", listLevel);
			m.put("stripLeading", !CanEdit);
			setupGetArticleListMacros(m);
			NameAddressStack s = new NameAddressStack(State.State,m);
			return new object[] { s, filterSort as IBizObj };
		}

		protected virtual void setupGetArticleListMacros(FlexiMap m)
		{
		}

		protected override object[] getDetailsBizRuleParameters(object bizObjKey)
		{
			DetailLevel dl = DetailLevel.fullDetails;
			
			if(State.State.get("displayDetailLevel") is DetailLevel)
				dl = (DetailLevel) State.State.get("displayDetailLevel");
			bool shouldIncrement = Cmn.IsEmpty(State.State.get("incrementCounts")) || Cmn.IsTrue(State.State.get("incrementCounts"));

            bool stripLeading = true;
            if (CanEdit)
                stripLeading = false;
			return new object[] { bizObjKey, true, dl, shouldIncrement, stripLeading, null };
		}

		protected override object[] getDeleteRuleParameters(object bizObjKey)
		{
			return new object[] { bizObjKey, true };
		}

		protected override object[] getUpdateBizRuleParameters(IBizObj bizObj)
		{
			string treeName = State.State.get("objectTreeName") as string;
			if (!Cmn.IsEmpty(treeName))
				bizObj.put("treeName", treeName);
			return new object[] { bizObj };
		}

        public override void showData(ForceLevel level)
        {
            base.showData(level);
			if (m_userArtFormData != null || Cmn.IsTrue(m_procState.get("pushFormData")))
            {
				var formData = m_userArtFormData!=null?m_userArtFormData:m_procState.get("formData");
                if (formData != null)
                {
					List<IBizObjDisplay> detailDisplays = m_procState.getDetailsDisplays();
                    if (detailDisplays != null)
                        foreach (IBizObjDisplay disp in detailDisplays)
                            if (disp is IUserFormDisplay)
                                ((IUserFormDisplay)disp).showArtFormData(formData);
                }
            }
        }

		public void generateFromYouTube(object infoObj)
		{
			IBizObj info = infoObj as IBizObj;
			IBizObj a = CurrentBizObj;

			if (info != null && a!=null)
			{
				info.put("baseArticleUniqueName", a.get("uniqueTitle").ToString().Length==0 ? a.get("id") : a.get("uniqueTitle"));
				App.ruleMgr.execute("uploadYoutubeArticles", null, null, new object[] { info });
			}
		}

		public void clearPrimaryPicture()
		{
			IResults rc = App.ruleMgr.execute("addPrimaryMedia", "", CurrentBizObj.get("id"));
			getCurrentBizObj();
		}

		public void setPrimaryPicture(object picInfo)
		{
			if (picInfo != null)
			{
				string pictureName = picInfo as string;
				IResults rc = App.ruleMgr.execute("addPrimaryMedia", pictureName, CurrentBizObj.get("id"));
				getCurrentBizObj();
			}
		}
		public void generateFromMedia(object medias)
		{
			IBizObjList mediaList = medias as IBizObjList;
			if (mediaList != null)
			{
				Swaf.BGuid.Guid parentId = CurrentBizObj.get("id") as Swaf.BGuid.Guid;
				if (parentId == null)
				{
					displayMessageFromBizRuleException("Error-CannotFindArticle", new BaseException("Article Id not found."));
					return;
				}
				IResults rc = App.ruleMgr.execute("generateArticleFromMedia", parentId, mediaList);
				if (rc.ExceptionInfo != null)
					displayMessageFromBizRuleException("Error-GeneratingArticlesFromMediaList", rc.ExceptionInfo);
				else
					clearDependentChildBizProcs();
			}
		}

		public override void bizObjCheckedChanged(IBizObjList uncheckedElements, IBizObjList checkedElements)
		{
			m_checkedArticles = checkedElements;
		}

		public void switchTranslationMode()
		{
			this.showData(ForceLevel.mustShowGetDetailsDataIfNeeded);
		}

		public override void deleteBizObj()
		{
			updateBizObj(true);
			if (m_checkedArticles != null && m_checkedArticles.numElements > 0)
			{
				foreach (IBizObj art in m_checkedArticles)
					base.deleteBizObj(art.KeyValue);
				clearRetrievedData();
				clearDependentChildBizProcs();
			}
			else
				base.deleteBizObj();
		}

		public void translateArticle()
		{
			updateBizObj(true);
			IResults rc = App.ruleMgr.execute("translateArticle", CurrentBizObj, (Swaf.BGuid.Guid)null);
			getCurrentBizObj();
		}

		protected override void getCurrentBizObj()
		{
			if(m_canChangeDetailsBizRule)
				if (!CanEdit && State.State.get("useTemplates") != null && State.State.get("useTemplates").ToString().ToLower().CompareTo("true") == 0)
					base.m_getBizObjDetailsRule = "getArticleTemplate";
				else
					base.m_getBizObjDetailsRule = "getArticleDetail";
			//m_currentArticleParentTree = null;
			base.getCurrentBizObj();

			if (m_currentBizObj != null)
				m_currentBizObj.put("translationId", m_translationId);
		}

		public override void cancelEdits()
		{
			App.sessionData["TranslationMode"] = false;
			base.cancelEdits();
		}

		public virtual void setPid(string newPid)
		{
			State.State.put("pid", newPid);
			State.State.put("id", null);
			clearRetrievedData();
            clearDependentChildBizProcs();
		}

		public override void updateBizObj(bool refreshOnly)
		{
			if(!refreshOnly && m_currentBizObj == null && !Cmn.IsEmpty(UseAssociationName))
				addNewBizObj();

			base.updateBizObj(refreshOnly);
			if(m_currentBizObj != null)
				m_translationId = m_currentBizObj.get("translationId") as Swaf.BGuid.Guid;
		}

        public virtual void updateArtForm(object formData)
        {
            if (!Cmn.IsEmpty(m_updateArtFormBizRule))
            {
				object[] ruleParams = getUpdateArtFormBizRuleParams(formData);
                IResults rc = App.ruleMgr.execute(m_updateArtFormBizRule, ruleParams);
				if (rc.ExceptionInfo == null)
				{
					List<string> failures = rc.CallResults as List<string>;
					if (failures != null)
					{
						foreach (string failure in failures)
						{
							FlexiMap m = new FlexiMap();
							m["failureType"] = failure;
							displayMessage("Error-InvalidArtFormValue", m);
						}
						m_userArtFormData = ((IBizObj)ruleParams[0]).get("formData").ToString();
					}
					else
					{
						string readMoreJump = (string)CurrentBizObj.get("readMoreJump");
						if (Cmn.IsEmpty(readMoreJump))
							displayMessage("Info-ArtFormSubmittedSuccessfully");
						else
							m_procState.BPC.HostView.gotoView(readMoreJump);
					}
				}
				else
					displayMessage("Error-ArtFormSubmitGeneralFailure");
            }
        }

        public virtual object[] getUpdateArtFormBizRuleParams(object formData)
        {
            IBizObj artForm = App.bizObjMgr.create("ArticleForm");
            artForm.put("id", new Swaf.BGuid.Guid());
            artForm.put("article.id", CurrentBizObj.get("id"));
            artForm.put("article.uniqueTitle", CurrentBizObj.get("uniqueTitle"));
            artForm.put("formData", formData);
            return new object[] { artForm };
        }

		protected virtual void undeleteBizObj()
		{
			object key = m_procState.get("id");
			IResults rc = App.ruleMgr.execute("undeleteArticle", key);
		}

        public void moveSelectedUnderParent(object parentId)
        {
            updateBizObj(true);
            if (m_checkedArticles != null && m_checkedArticles.numElements > 0)
            {
                App.Log.println(Swaf.Logging.LoggingLevels.Medium, "moveSelectedUnderParent - {1} Products Selected. BizProc.Id='{0}''", Id, m_checkedArticles.numElements);
                IResults rc = App.ruleMgr.execute("moveArticlesToNewParent", parentId, m_checkedArticles);
                clearRetrievedData();
            }
            else
                App.Log.println(Swaf.Logging.LoggingLevels.Medium, "moveSelectedUnderParent - No Products Selected. BizProc.Id='{0}''", Id);
        }



		protected override void setupActions()
		{
			base.setupActions();
			Actions.addAction(new GenericAction("UndeleteBizObj", false, undeleteBizObj, this));
            Actions.addAction(new GenericAction("MoveSelectUnderParent", false, false, this, new ActionParamTrigger(moveSelectedUnderParent), new object[] { }));
            Actions.addAction(new GenericAction("ClearArticlePicture", false, clearPrimaryPicture, this));
            Actions.addAction(new GenericAction("GenerateFromYouTube", true, false, this, new ActionParamTrigger(generateFromYouTube), new object[] { }));
            Actions.addAction(new GenericAction("SetArticlePicture", true, false, this, new ActionParamTrigger(setPrimaryPicture), new object[] { }));
            Actions.addAction(new GenericAction("GenerateFromMedia", true, false, this, new ActionParamTrigger(generateFromMedia), new object[] { }));
            Actions.addAction(new GenericAction("SwitchTranslation", false, switchTranslationMode, this));
			Actions.addAction(new GenericAction("TranslateArticle", true, translateArticle, this));
            Actions.addAction(new GenericAction("UpdateArtForm", false, true, this, new ActionParamTrigger(updateArtForm), new object[] {}));
		}
		public override void updateActionState()
		{
			base.updateActionState();
			Privileges curPriv = CurrentEditPrivilege;
			bool isNew = State.InProgressAddBizObj != null;
			((GenericAction)Actions["UndeleteBizObj"]).Availability =
				(isNew || curPriv == Privileges.None) ? ActionAvailability.none :
				(curPriv >= Privileges.Delete) ? ActionAvailability.enabled : ActionAvailability.disabled;
            ((GenericAction)Actions["MoveSelectUnderParent"]).Availability =
                (!CanEdit || isNew || curPriv == Privileges.None) ? ActionAvailability.none :
                (curPriv >= Privileges.Delete) ? ActionAvailability.enabled : ActionAvailability.disabled;
            
            ((GenericAction)Actions["ClearArticlePicture"]).Availability = CanEdit ? ActionAvailability.enabled : ActionAvailability.none;
			((GenericAction)Actions["GenerateFromYouTube"]).Availability = CanEdit ? ActionAvailability.enabled : ActionAvailability.none;
            ((GenericAction)Actions["SetArticlePicture"]).Availability = CanEdit ? ActionAvailability.enabled : ActionAvailability.none;
            ((GenericAction)Actions["GenerateFromMedia"]).Availability = CanEdit ? ActionAvailability.enabled : ActionAvailability.none;
			((GenericAction)Actions["SwitchTranslation"]).Availability = CanEdit ? ActionAvailability.enabled : ActionAvailability.none;
			((GenericAction)Actions["TranslateArticle"]).Availability = CanEdit ? ActionAvailability.enabled : ActionAvailability.none;
			//The following if statement is troublesome.  By using CurrentBizObj, it forces the bizproc to call the getCurrentBizObj method
			//even when under some situations it wouldnt need to get called.  However, its the only way to know if the given article
			//if(m_currentBizObj != null)
			if(m_procState.getDetailsDisplays().Count > 0 && CurrentBizObj != null)
				((GenericAction)Actions["UpdateArtForm"]).Availability = (HasBizObj && string.Compare((string)CurrentBizObj.get("suggestedDisplayType"), "-ArtForm") == 00) ? ActionAvailability.enabled : ActionAvailability.none;

		}
		public bool TranslationMode
		{
			get
			{
				if(App.sessionData["TranslationMode"]!=null)
					return (bool)App.sessionData["TranslationMode"];
				return false;
			}
		}

		protected bool HasBizObj
		{
			get
			{
				List<IBizObjDisplay> detailDisplays = m_procState.getDetailsDisplays();
				bool hasEm = detailDisplays != null && detailDisplays.Count > 0;
				if(hasEm)
				{
					bool anyVis = false;
					foreach(IBizObjDisplay disp in detailDisplays)
						if (disp.isDisplayingContent)
						{
							anyVis = true;
							break;
						}
					hasEm = anyVis && CurrentBizObj != null;
				}
				return hasEm;
			}
		}
	}
}
